﻿//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Microsoft Public License.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace AstoriaOverAstoria
{
    using System;
    using System.Data.Services.Providers;
    using System.Diagnostics;
    using System.Linq.Expressions;

    /// <summary>Expression annotations which can store resource annotations (type, properties and so on).</summary>
    internal class ExpressionResourceAnnotations : Annotations<Expression>
    {
        /// <summary>The annotation name for ResourceProperty annotation.</summary>
        public const string ResourcePropertyAnnotationName = "ResourceProperty";

        /// <summary>The annotation name for ResourceType annotation.</summary>
        public const string ResourceTypeAnnotationName = "ResourceType";

        /// <summary>Annotates the specified <paramref name="expr"/> with the <paramref name="property"/>.</summary>
        /// <param name="expr">The expression to annotation.</param>
        /// <param name="property">The resource property the <paramref name="expr"/> evaluates to.</param>
        /// <returns>The <paramref name="expr"/> so that it's easier to use.</returns>
        public Expression AnnotateResourceProperty(Expression expr, ResourceProperty property)
        {
            this.SetAnnotation(expr, ResourcePropertyAnnotationName, property);
            this.SetAnnotation(expr, ResourceTypeAnnotationName, property.ResourceType);
            return expr;
        }

        /// <summary>Annotates the specified <paramref name="expr"/> with the <paramref name="type"/>.</summary>
        /// <param name="expr">The expression to annotation.</param>
        /// <param name="type">The resource type the <paramref name="expr"/> evaluates to.</param>
        /// <returns>The <paramref name="expr"/> so that it's easier to use.</returns>
        public Expression AnnotateResourceType(Expression expr, ResourceType type)
        {
            this.SetAnnotation(expr, ResourceTypeAnnotationName, type);
            return expr;
        }

        /// <summary>Applies resource type annotation from the <paramref name="exprSource"/> to the <paramref name="exprTarget"/>.</summary>
        /// <param name="exprSource">The expression to take the annotation from.</param>
        /// <param name="exprTarget">The expression to apply the annotation to.</param>
        /// <returns>The <paramref name="exprTarget"/> so that it's easier to use.</returns>
        public Expression PropagateResourceType(Expression exprSource, Expression exprTarget)
        {
            ResourceType type = this.GetResourceType(exprSource);
            return this.AnnotateResourceType(exprTarget, type);
        }

        /// <summary>Determines the resource type annotation.</summary>
        /// <param name="expr">The expression to get the annotation from.</param>
        /// <returns>The resource type annotation or null if none is present.</returns>
        public ResourceType GetResourceType(Expression expr)
        {
            return this[expr, ResourceTypeAnnotationName] as ResourceType;
        }

        /// <summary>Determines the resource property annotation.</summary>
        /// <param name="expr">The expression to get the annotation from.</param>
        /// <returns>The resource property annotation or null if none is present.</returns>
        public ResourceProperty GetResourceProperty(Expression expr)
        {
            return this[expr, ResourcePropertyAnnotationName] as ResourceProperty;
        }
    }
}